﻿using System;
using System.Collections.Generic;
using System.Text;
using Chaliy.DbPro.Generators.TextAuthoring.Configuration;
using System.Collections.ObjectModel;

namespace Chaliy.DbPro.Generators.TextAuthoring
{
    public class TermSelector
    {
        #region Fields

        private double weightSum;
        private int itemCount;
        private double[] positions;
        private bool statisticsCreated;
		private readonly ITermAccessor terms;        
        private Random randomSelector;        

        #endregion

        #region Constructors

		public TermSelector(ITermAccessor terms)
        {
            if (terms == null)
            {
                throw new ArgumentNullException("terms");
            }

            this.terms = terms;            
        }

        #endregion

        #region Properties

        protected double WeightSum
        {
            get
            {
                this.EnsureStatisticsCreated();
                return this.weightSum;
            }
        }       

        protected double[] Positions
        {
            get
            {
                this.EnsureStatisticsCreated();
                return this.positions; 
            }
        }

        protected Random RandomSelector
        {
            get
            {
                if (this.randomSelector == null)
                {
                    this.randomSelector = new Random();
                }
                return this.randomSelector;
            }            
        }

		protected ITermAccessor Terms
        {
            get 
            {
                return this.terms; 
            }
        } 

        #endregion

        #region Methods

        private void EnsureStatisticsCreated()
        {
            if (this.statisticsCreated == false)
            {
				ITermAccessor terms = this.Terms;
                int itemCount = terms.Count;
                double[] positions = new double[itemCount];
                double weightSum = 0.0;

				int i = 0;
				foreach (TermConfiguration term in terms)
				{
					positions[i] = term.Weight;
					weightSum += term.Weight;
					i++;
				}
                
                this.weightSum = weightSum;
                this.itemCount = itemCount;
                this.positions = positions;
                this.statisticsCreated = true;
            }
        }

        public string GetNextTerm()
        {
			if (this.Terms.Count == 0)
			{
				throw TextAuthorException.CreateTermsCanNotBeEmpty();
			}
            double position = this.RandomSelector.NextDouble() * this.WeightSum;
            int index = this.GetIndex(position);			
            return this.Terms[index];
        }

        private int GetIndex(double position)
        {
            double[] positions = this.Positions;
            for (int i = 0; i < positions.Length; i++)
            {
				if (positions[i] < position)
                {					
                    return i;
                }
            }
            return positions.Length - 1; // Return last index.
        }

        #endregion        
    }
}
